package com.triones.biz.infra.service.file.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.triones.biz.infra.entity.file.bo.FileConfigBO;
import com.triones.framework.common.enums.BooleanNumberEnum;
import com.triones.framework.common.util.json.JsonUtils;
import com.triones.framework.common.util.validation.ValidationUtils;
import com.triones.framework.file.core.client.FileClient;
import com.triones.framework.file.core.client.FileClientConfig;
import com.triones.framework.file.core.client.FileClientFactory;
import com.triones.framework.file.core.enums.FileStorageEnum;
import com.triones.biz.infra.convert.file.FileConfigConvert;
import com.triones.biz.infra.entity.file.FileConfigDO;
import com.triones.biz.infra.entity.file.vo.FileConfigVO;
import com.triones.biz.infra.mapper.file.FileConfigMapper;
import com.triones.biz.infra.mq.producer.file.FileConfigProducer;
import com.triones.biz.infra.service.file.FileConfigService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.validation.Validator;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import static com.triones.biz.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER;
import static com.triones.biz.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS;

/**
 * 文件配置 Service 接口实现
 *
 * @author triones
 * 2023-09-19
 */
@Service
@Slf4j
public class FileConfigServiceImpl implements FileConfigService {
    @Resource
    private FileClientFactory fileClientFactory;
    /**
     * Master FileClient 对象，有且仅有一个，即 {@link FileConfigDO#getMaster()} 对应的
     */
    @Getter
    private FileClient masterFileClient;

    @Resource
    private FileConfigMapper fileConfigMapper;

    @Resource
    private FileConfigProducer fileConfigProducer;

    @Resource
    private Validator validator;

    /**
     * 初始化文件客户端
     */
    @Override
    @PostConstruct
    public void initLocalCache() {
        // 第一步：查询数据
        List<FileConfigDO> configs = fileConfigMapper.selectList();
        log.info("[initLocalCache][缓存文件配置，数量为:{}]", configs.size());
        // 第二步：构建缓存：创建或更新文件 Client
        configs.forEach(config -> {
            if (config.getConfig() != null) {
                fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
                // 如果是 master，进行设置
                if (BooleanNumberEnum.YES.getCode().equals(config.getMaster())) {
                    masterFileClient = fileClientFactory.getFileClient(config.getId());
                }
            }
        });
    }

    /**
     * 查询文件配置
     */
    @Override
    public FileConfigVO queryById(Long id) {
        return fileConfigMapper.selectVoById(id);
    }

    /**
     * 查询文件配置列表
     */
    @Override
    public TableDataInfo<FileConfigVO> queryPageList(FileConfigBO bo, PageQuery pageQuery) {
        LambdaQueryWrapper<FileConfigDO> lqw = buildQueryWrapper(bo);
        Page<FileConfigVO> result = fileConfigMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询文件配置列表
     */
    @Override
    public List<FileConfigVO> queryList(FileConfigBO bo) {
        LambdaQueryWrapper<FileConfigDO> lqw = buildQueryWrapper(bo);
        return fileConfigMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<FileConfigDO> buildQueryWrapper(FileConfigBO bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<FileConfigDO> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getName()), FileConfigDO::getName, bo.getName());
        lqw.eq(bo.getStorage() != null, FileConfigDO::getStorage, bo.getStorage());
        lqw.eq(bo.getMaster() != null, FileConfigDO::getMaster, bo.getMaster());
        return lqw;
    }

    /**
     * 新增文件配置
     */
    @Override
    public Boolean insertByBo(FileConfigBO bo) {
        // 插入
        FileConfigDO add = FileConfigConvert.INSTANCE.convert(bo)
            .setConfig(parseClientConfig(bo.getStorage(), bo.getConfig()))
            .setMaster(BooleanNumberEnum.NO.getCode()); // 默认非 master
        validEntityBeforeSave(add);
        boolean flag = fileConfigMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
            // 发送刷新配置的消息
            fileConfigProducer.sendFileConfigRefreshMessage();
        }
        return flag;
    }

    /**
     * 修改文件配置
     */
    @Override
    public Boolean updateByBo(FileConfigBO bo) {
        // 校验存在
        FileConfigDO config = validateFileConfigExists(bo.getId());
        // 更新
        FileConfigDO update = FileConfigConvert.INSTANCE.convert(bo)
            .setConfig(parseClientConfig(config.getStorage(), bo.getConfig()));
        validEntityBeforeSave(update);
        boolean flag = fileConfigMapper.updateById(update) > 0;
        if (flag) {
            // 发送刷新配置的消息
            fileConfigProducer.sendFileConfigRefreshMessage();
        }
        return flag;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(FileConfigDO entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除文件配置
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            for (Long id : ids) {
                // 校验存在
                FileConfigDO config = validateFileConfigExists(id);
                if (BooleanNumberEnum.YES.getCode().equals(config.getMaster())) {
                    throw new ServiceException(FILE_CONFIG_DELETE_FAIL_MASTER.getMsg());
                }
            }
        }
        return fileConfigMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 更新文件配置为 Master
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateFileConfigMaster(Long id) {// 校验存在
        validateFileConfigExists(id);
        // 更新其它为非 master
        fileConfigMapper.updateBatch(new FileConfigDO().setMaster(BooleanNumberEnum.NO.getCode()));
        // 更新
        fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(BooleanNumberEnum.YES.getCode()));
        // 发送刷新文件配置的消息
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

            @Override
            public void afterCommit() {
                log.debug("发送刷新文件配置的消息");
                fileConfigProducer.sendFileConfigRefreshMessage();
            }

        });
    }

    /**
     * 获得指定编号的文件客户端
     *
     * @param id 配置编号
     * @return 文件客户端
     */
    @Override
    public FileClient getFileClient(Long id) {
        return fileClientFactory.getFileClient(id);
    }

    private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) {
        // 获取配置类
        Class<? extends FileClientConfig> configClass = FileStorageEnum.getByStorage(storage)
            .getConfigClass();
        FileClientConfig clientConfig = JsonUtils.parseObject2(JsonUtils.toJsonString(config), configClass);
        // 参数校验
        ValidationUtils.validate(validator, clientConfig);
        // 设置参数
        return clientConfig;
    }

    private FileConfigDO validateFileConfigExists(Long id) {
        FileConfigDO config = fileConfigMapper.selectById(id);
        if (config == null) {
            throw new ServiceException(FILE_CONFIG_NOT_EXISTS.getMsg());
        }
        return config;
    }


}
